﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Security.Policy;

namespace HomeFramework.Core
{
    [Obsolete]
    internal sealed class AppDomainEnvelope<T, RQ, RE> : IDisposable
        where T : AppDomainGateway<RQ, RE>, new()
        where RQ : struct
        where RE : struct
    {
        private string DomainName;
        private AppDomain Domain;

        public AppDomainEnvelope()
        {
            DomainName = GetType().Name + Guid.NewGuid().ToString();
            Domain = AppDomain.CreateDomain(DomainName, new Evidence(AppDomain.CurrentDomain.Evidence), AppDomain.CurrentDomain.SetupInformation);

        }

        public RE ProcessGateway(RQ request, byte[] AssemblyData, params byte[][] references)
        {
            using (T Gateway = (T)Domain.CreateInstanceAndUnwrap(typeof(T).Assembly.FullName, typeof(T).FullName))
            {
                Gateway.InitializeGateway(AssemblyData, references);
                return Gateway.ProcessGateway(request);
            }
        }

        public void Dispose()
        {
            AppDomain.Unload(Domain);
        }
    }

    [Obsolete]
    internal abstract class AppDomainGateway<RQ, RE> : MarshalByRefObject, IDisposable
        where RQ : struct
        where RE : struct
    {
        protected Assembly Assembly;
        protected readonly List<Assembly> References = new List<Assembly>();
        
        public void InitializeGateway(byte[] AssemblyData, params byte[][] references)
        {
            AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

            foreach (var r in references)
               References.Add(LoadAssembly(r));

            Assembly = LoadAssembly(AssemblyData);
        }

        public abstract RE ProcessGateway(RQ request);

        private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            return AppDomain.CurrentDomain.GetAssemblies().SingleOrDefault(x => x.FullName == args.Name);
        }

        protected Assembly LoadAssembly(byte[] data)
        {
            return AppDomain.CurrentDomain.Load(data);
        }

        protected dynamic Instance(string TypeName)
        {
            return AppDomain.CurrentDomain.CreateInstanceAndUnwrap(Assembly.FullName, TypeName);
        }

        public void Dispose()
        {
        }
    }
}
